package com.baidu.acg.industry.bigdata.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baidu.acg.industry.bigdata.config.ApplicationConfiguration;
import com.baidu.acg.industry.bigdata.model.*;
import com.baidu.acg.industry.bigdata.utils.MinioUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.async.ResultCallback;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.ExecCreateCmdResponse;
import com.github.dockerjava.api.command.InspectContainerResponse;
import com.github.dockerjava.api.exception.ConflictException;
import com.github.dockerjava.api.exception.NotFoundException;
import com.github.dockerjava.api.model.*;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.command.ExecStartResultCallback;
import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))

public class YongJiModelService {

    private final ApplicationConfiguration modelConfiguration;
    private final MinioUtil minioUtil;
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private final ApplicationConfiguration applicationConfiguration;

    public Map<String, String> modelTrain(String localDirPath, String prefix) {
        Map<String, String> fileDownPathMap = new HashMap<>();
        Map<String, String> newMap = new HashMap<>();
        try {
            fileDownPathMap = minioUtil.uploadDirectory(modelConfiguration.getBucketName(), localDirPath, prefix);
            for (Map.Entry<String, String> entry : fileDownPathMap.entrySet()) {
                String newValue = modifyValue(entry.getValue()); // 修改value的逻辑
                newMap.put(entry.getKey(), newValue);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        // 将下面map中的value进行下载本地，然后给到模型去做模型训练
        for (Map.Entry<String, String> stringStringEntry : newMap.entrySet()) {
            try {
                minioUtil.downloadFile(modelConfiguration.getBucketName(), subStringUrl(stringStringEntry.getValue()),
                        modelConfiguration.getPreDealModelFilePath());
            } catch (Exception e) {
                log.error("download fail", e);
                throw new RuntimeException(e);
            }
        }
        return newMap;
    }


    // 拼接minio永久地址
    private String modifyValue(String value) {
        return modelConfiguration.getMinioEndpoint() + "/" + modelConfiguration.getBucketName() + "/" + value;
    }

    private String subStringUrl(String url) {
        // 定义正则表达式
        Pattern pattern = Pattern.compile(modelConfiguration.getBucketName() + "/(.*)");
        Matcher matcher = pattern.matcher(url);
        String targetPath = "";
        if (matcher.find()) {
            targetPath = matcher.group(1);
            log.info("截取结果: " + targetPath); // document/2025-03-30-15-44-33/train.log
        } else {
            log.info("未匹配到路径");
        }
        return targetPath;
    }
    @SneakyThrows
    public int generateTxtNotDownloadByAsy(MinioRequestTxt  minioRequestTxt){
        log.info("scenario目录详情:{}", minioRequestTxt.toString());
        DockerClient dockerClient = DockerClientBuilder.getInstance().build();
        //镜像名称
        String imageName = modelConfiguration.getModelImageVersion();
        //模型名称 zhongche-service- 随机Id
        String containerName = modelConfiguration.getModelTrainName() + "-" + generateCharId();

        //模型的m默认工作路径
        String modelDefaultWorkPath = modelConfiguration.getModelDefaultWorkPath();
        //宿主机脚本的挂载的文件路径
        String modelContainerHostInputPath = modelConfiguration.getModelContainerHostInputPath();
        //容器的交本文件路径，实际就是工作路径
        String modelContainerVolumeInputPath = modelConfiguration.getModelContainerVolumeInputPath();
        HashMap<String, String> map = new HashMap<>();
        //定位每个路径的位置
        for (String minioPath : minioRequestTxt.getMinioPaths()){
            String  temp=modelContainerVolumeInputPath+"/"+minioPath;
            map.put(temp,minioPath);
        }
        CreateContainerResponse container = null;
        try {
            // 创建容器配置（关键修改点）
            container = dockerClient.createContainerCmd(imageName)
                    .withName(containerName)
                    .withHostConfig(HostConfig.newHostConfig()
                            .withBinds(
                                    new Bind(modelContainerHostInputPath, new Volume(modelContainerVolumeInputPath)
                                    )
                            )  // 挂载卷[1,4](@ref)
                            .withNetworkMode("host")
                            // 网络模式[1](@ref)
                            .withShmSize(64L * 1024 * 1024 * 1024)
                            // 64GB共享内存[8](@ref)
                            .withDeviceRequests(List.of(
                                    // GPU配置[2,5](@ref)
                                    new DeviceRequest()
                                            .withDriver("nvidia")
                                            .withCount(0)
                                            .withCapabilities(List.of(List.of("gpu")))
                            ))
                    )
                    .withEnv(
                            // 环境变量配置[5,7](@ref)
                            "NVIDIA_DRIVER_CAPABILITIES=compute,utility",
                            "NVIDIA_VISIBLE_DEVICES=all"
                            // 容器级可见设备
                    )
                    .withWorkingDir(modelDefaultWorkPath)
                    // 工作目录[4](@ref)
                    .withCmd("tail", "-f", "/dev/null")
                    // 让容器持续运行
                    .exec();
            // 启动容器
            dockerClient.startContainerCmd(container.getId()).exec();
            log.info("GPU容器启动成功！ID: " + container.getId());
            generateTxtExecByAsy(map,modelContainerHostInputPath,dockerClient,container,minioRequestTxt);
            log.info("全部生成成功");
        } catch (Exception e){
            cleanupContainer(dockerClient,container);
            log.info("生成txt失败！操作失败提示信息，{}",e.getMessage());
            return -1;
        }
        log.info("异步调用结束，主线程返回成功");
        return 0;
    }
    public  void generateTxtExecByAsy(HashMap<String ,String > map,String  modelContainerHostInputPath,DockerClient dockerClient,CreateContainerResponse container,MinioRequestTxt minioRequestTxt){
        CompletableFuture.runAsync(() -> {
            log.info("异步开始生成txt");
            try {
                for (String path : map.keySet()) {
                    String fileName = "error.log";
                    Path tempPath = Paths.get(modelContainerHostInputPath+"/"+map.get(path));
                    Path errorLogPath = Paths.get( tempPath.getParent()+"/", fileName);
                    if (Files.exists(errorLogPath)){
                        Files.delete(errorLogPath);
                    }
                    ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(container.getId())
                            .withAttachStdout(true)
                            .withAttachStderr(true)
                            .withCmd(
                                    "python", "generate_snapshot_path.py",
                                    "--scenario_out",path,
                                    "--type", minioRequestTxt.getType()
                            )
                            .exec();
                    log.info("执行操作: {}",path);
                    ByteArrayOutputStream stdout = new ByteArrayOutputStream();
                    ByteArrayOutputStream stderr = new ByteArrayOutputStream();
                    dockerClient.execStartCmd(execCreateCmdResponse.getId())
                            .exec(new ExecStartResultCallback(stdout, stderr))
                            .awaitCompletion();
                    String errStr = stderr.toString(StandardCharsets.UTF_8);
                    if (!errStr.isBlank()){
                        log.info("错误结果: {}", errStr);
                        Files.write(errorLogPath, errStr.getBytes(StandardCharsets.UTF_8));
                    }
                }
                log.info("异步全部生成成功");
            } catch (Exception e){
                log.info("异步生成txt失败！操作失败提示信息，{}",e.getMessage());

            }
            finally {
                cleanupContainer(dockerClient,container);
            }
        });
    }




    public static void deleteDirectory(File dir) {
        if (dir.isDirectory()) {
            File[] children = dir.listFiles();
            if (children != null) {
                for (File child : children) {
                    deleteDirectory(child); // 递归删除子文件/子文件夹
                }
            }
        }
        dir.delete(); // 删除空目录或文件本身
    }
    @SneakyThrows
    public int generateTxtNotDownload(MinioRequestTxt  minioRequestTxt){
        log.info("scenario目录详情:{}", minioRequestTxt.toString());
        DockerClient dockerClient = DockerClientBuilder.getInstance().build();
        //镜像名称
        String imageName = modelConfiguration.getModelImageVersion();
        //模型名称
        String containerName = modelConfiguration.getModelTrainName() + "-" + generateCharId();
        //宿主机minio路径
        String  minioOutPath=modelConfiguration.getMinioOutputPath();
        //模型minio   volume地址，和训练不同的是这里不再挂载到train_model_address目录中，这次挂载到minioData,区分

        String modelTrainMinioPath = modelConfiguration.getModelTrainMinioPath();
        //模型的m默认工作路径
        String modelDefaultWorkPath = modelConfiguration.getModelDefaultWorkPath();
        //宿主机脚本的挂载的文件路径
        String modelContainerHostInputPath = modelConfiguration.getModelContainerHostInputPath();
        //容器的交本文件路径，实际就是工作路径
        String modelContainerVolumeInputPath = modelConfiguration.getModelContainerVolumeInputPath();
        HashMap<String, String> map = new HashMap<>();
        //定位每个路径的位置
        for (String minioPath : minioRequestTxt.getMinioPaths()){
            String  temp=modelTrainMinioPath+"/"+minioPath;
            map.put(temp,minioPath);
        }
        CreateContainerResponse container = null;
        String errorMinioPath=null;
        try {
            // 创建容器配置（关键修改点）
            container = dockerClient.createContainerCmd(imageName)
                    .withName(containerName)
                    .withHostConfig(HostConfig.newHostConfig()
                            .withBinds(
                                    new Bind(modelContainerHostInputPath, new Volume(modelContainerVolumeInputPath)
                                    ),
                                    new Bind(minioOutPath, new Volume(modelTrainMinioPath)
                                    )
                            )  // 挂载卷[1,4](@ref)
                            .withNetworkMode("host")  // 网络模式[1](@ref)
                            .withShmSize(64L * 1024 * 1024 * 1024)  // 64GB共享内存[8](@ref)
                            .withDeviceRequests(List.of(  // GPU配置[2,5](@ref)
                                    new DeviceRequest()
                                            .withDriver("nvidia")
                                            .withCount(0)
                                            .withCapabilities(List.of(List.of("gpu")))
                            ))
                    )
                    .withEnv(  // 环境变量配置[5,7](@ref)
                            "NVIDIA_DRIVER_CAPABILITIES=compute,utility",
                            "NVIDIA_VISIBLE_DEVICES=all"  // 容器级可见设备
                    )
                    .withWorkingDir(modelDefaultWorkPath)  // 工作目录[4](@ref)
                    .withCmd("tail", "-f", "/dev/null")  // 让容器持续运行
                    .exec();
            // 启动容器
            dockerClient.startContainerCmd(container.getId()).exec();
            log.info("GPU容器启动成功！ID: " + container.getId());
            for (String path : map.keySet()) {
                log.info("正在处理目录文件: {}",path);
                errorMinioPath=path;
                ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(container.getId())
                        .withAttachStdout(true)
                        .withAttachStderr(true)
                        .withCmd(
                                "python", "generate_snapshot_path.py",
                                "--scenario_out",path,
                                "--type", minioRequestTxt.getType()
                        )
                        .exec();

                dockerClient.execStartCmd(execCreateCmdResponse.getId())
                        .exec(new ExecStartResultCallback(System.out, System.err))
                        .awaitCompletion();
                log.info("执行操作: {}",path);
            }
            log.info("全部生成成功");
        }catch (NotFoundException e) {
            log.error("镜像不存在: " + imageName);
            return -1;
        } catch (ConflictException e) {
            log.error("容器名称冲突: " + containerName);
            return -1;
        }catch (Exception e){
            log.info("生成txt失败！操作失败提示信息:{},操作失败路径，{}",e.getMessage(),errorMinioPath);
            return -1;
        }
        finally {
            cleanupContainer(dockerClient,container);
        }
        return 0;
    }
    @SneakyThrows
    public int generateTxt(MinioRequestTxt minioRequestTxt) {
        log.info("scenario目录详情:{}", minioRequestTxt.toString());
        DockerClient dockerClient = DockerClientBuilder.getInstance().build();
        String imageName = modelConfiguration.getModelImageVersion(); // 替换为你的镜像名称
        String containerName = modelConfiguration.getModelTrainName() + "-" + generateCharId();
        String hostConfigDir = modelConfiguration.getModelContainerHostPath();
        // 宿主机配置文件目录
        String containerConfigPath = modelConfiguration.getModelContainerVolumePath();
        // 容器内挂载路径
        String modelDefaultWorkSpace = modelConfiguration.getModelDefaultWorkPath();
        // 模型默认工作路径
        //MinioData  文件夹
        List<String> minioPaths = minioRequestTxt.getMinioPaths();
        String modelContainerHostInputPath = modelConfiguration.getModelContainerHostInputPath();
        //// 模型用户上传的文件映射
        String localPath = modelContainerHostInputPath+"/minioData";
        //// 模型用户的临时minioData文件
        File localDir = new File(localPath);
        if (!localDir.exists()) {
            localDir.mkdirs(); //
        }
        log.info("创建minio临时目录完成");
        for ( String minioPath : minioPaths){
            minioUtil.downloadDirectory(applicationConfiguration.getBucketName(),minioPath,localPath);
            log.info("下载目录完成：{}",minioPath);
        }
//        minioUtil.downloadDirectory(applicationConfiguration.getBucketName(),"12345678/Scenario_1/scenario_1/scenario_1_out/",localPath);
        log.info("minio下载完成");
        long totalFiles = Files.walk(Paths.get(localPath))
                .filter(Files::isRegularFile)
                .count();
        log.info("本次共下载文件 {} 个，存放于 {}", totalFiles, localPath);
        CreateContainerResponse container = null;
        String errorMinioPath=null;
        try {
            // 创建容器配置（关键修改点）
            container = dockerClient.createContainerCmd(imageName)
                    .withName(containerName)
                    .withHostConfig(HostConfig.newHostConfig()
                            .withBinds(new Bind(hostConfigDir, new Volume(containerConfigPath)),
                                    new Bind( modelConfiguration.getModelContainerHostInputPath(),  // 模型用户上传的文件映射
                                            new Volume(modelConfiguration.getModelContainerVolumeInputPath()))   // 模型用户上传的文件映射到容器内路径
                            )  // 挂载卷[1,4](@ref)
                            .withNetworkMode("host")  // 网络模式[1](@ref)
                            .withShmSize(64L * 1024 * 1024 * 1024)  // 64GB共享内存[8](@ref)
                            .withDeviceRequests(List.of(  // GPU配置[2,5](@ref)
                                    new DeviceRequest()
                                            .withDriver("nvidia")
                                            .withCount(0)
                                            .withCapabilities(List.of(List.of("gpu")))
                            ))
                    )
                    .withEnv(  // 环境变量配置[5,7](@ref)
                            "NVIDIA_DRIVER_CAPABILITIES=compute,utility",
                            "NVIDIA_VISIBLE_DEVICES=all"  // 容器级可见设备
                    )
                    .withWorkingDir(modelDefaultWorkSpace)  // 工作目录[4](@ref)
                    .withCmd("tail", "-f", "/dev/null")  // 让容器持续运行
                    .exec();
            // 启动容器
            dockerClient.startContainerCmd(container.getId()).exec();
            log.info("GPU容器启动成功！ID: " + container.getId());
            for (String minioPath : minioPaths) {
                errorMinioPath=minioPath;
                ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(container.getId())
                        .withAttachStdout(true)
                        .withAttachStderr(true)
                        .withCmd(
                                "python", "generate_snapshot_path.py",
                                "--scenario_out", modelConfiguration.getModelContainerVolumeInputPath() + "/minioData/" + minioPath,
                                "--type", minioRequestTxt.getType()
                        )
                        .exec();
                log.info("执行操作: {}",modelConfiguration.getModelContainerVolumeInputPath() + "/minioData/" + minioPath);
                dockerClient.execStartCmd(execCreateCmdResponse.getId())
                        .exec(new ExecStartResultCallback(System.out, System.err))
                        .awaitCompletion();
                if (minioPath.endsWith("/")) {
                    minioPath = minioPath.substring(0, minioPath.length() - 1);
                }
                minioUtil.uploadFile(applicationConfiguration.getBucketName(), localPath + "/" + minioPath + ".txt", minioPath + ".txt");
            }
//            minioUtil.uploadFile(applicationConfiguration.getBucketName(),"/data/zhongche_store/data/zhongche/minioData/12345678/Scenario_1/scenario_1/scenario_1_out.txt","12345678/Scenario_1/scenario_1/scenario_1_out.txt");
            log.info("全部上传成功");
        }catch (NotFoundException e) {
            log.error("镜像不存在: " + imageName);
            return -1;
        } catch (ConflictException e) {
            log.error("容器名称冲突: " + containerName);
            return -1;
        }catch (Exception e){
            log.info("生成txt失败！操作失败提示信息:{},操作失败路径，{}",e.getMessage(),errorMinioPath);
            return -1;
        }
        finally {
            cleanupAsync(dockerClient,container,localPath);
        }
        return 0;
    }
    @SneakyThrows
    public String runModel(ModelTrainRequest modelTrainRequest) {
        log.info("模型训练入参:{}", modelTrainRequest);
        // 1. 初始化 Docker 客户端（默认连接本地 Docker 守护进程）
        DockerClient dockerClient = DockerClientBuilder.getInstance().build();

        // 2. 定义容器参数
        String imageName = modelConfiguration.getModelImageVersion(); // 替换为你的镜像名称
        String containerName = modelConfiguration.getModelTrainName() + "-" + generateCharId();
        String hostConfigDir = modelConfiguration.getModelContainerHostPath(); // 宿主机配置文件目录
        String containerConfigPath = modelConfiguration.getModelContainerVolumePath(); // 容器内挂载路径
        String modelDefaultWorkSpace = modelConfiguration.getModelDefaultWorkPath(); // 模型默认工作路径

        String uuidPath = generateCharId();
        String minioBucketPath = modelConfiguration.getModelContainerVolumePath() + "/" + modelTrainRequest.getTaskId() + "_" + uuidPath;
        log.info("模型产物输出地址=>" + minioBucketPath);

        List<String> commandParts = new ArrayList<>();

        String cudaDevices = modelTrainRequest.getCudaVisbleDevices();
        commandParts.add("CUDA_VISIBLE_DEVICES=" + cudaDevices);

        // 按逗号分割 GPU 列表
        String[] devicesArray = cudaDevices.split(",");
        if (devicesArray.length >= 2) {
            // 当有两个或以上 GPU 时，使用分布式启动方式
            commandParts.add("python3.10");
            commandParts.add("-m");
            commandParts.add("paddle.distributed.launch");
            commandParts.add("main.py");
        } else {
            // 当只有一个 GPU 时，直接运行
            commandParts.add("python3.10");
            commandParts.add("main.py");
        }

        if (modelTrainRequest.getModelDatasetType().equals("motor")) {
            commandParts.add("-cn");
            commandParts.add("motor_thermal.yaml");
            log.info("当前数据集类型: " + modelTrainRequest.getModelDatasetType());
        } else if (modelTrainRequest.getModelDatasetType().equals("convertor")) {
            commandParts.add("-cn");
            commandParts.add("convertor_thermal.yaml");
            log.info("当前数据集类型: " + modelTrainRequest.getModelDatasetType());
        }

        commandParts.add("output_dir=" + minioBucketPath.trim());
        // 添加 DATA.points_bin_path 参数
        addParamsFromList(commandParts, "++TRAIN.points_bin_path", modelTrainRequest.getTrainPointBinPath(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 DATA.stl_path 参数
        addParamsFromList(commandParts, "++TRAIN.stl_path", modelTrainRequest.getTrainStlPath(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 TRAIN.data_dir 参数
        addParamsFromList(commandParts, "++TRAIN.data_dir", modelTrainRequest.getTrainDataDir(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 TRAIN.snapshots_path 参数
        addParamsFromList(commandParts, "++TRAIN.snapshots_path", modelTrainRequest.getTrainSnapshotsPath(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 TRAIN.scenario_exc_csv_path 参数
        addParamsFromList(commandParts, "++TRAIN.scenario_exc_csv_path", modelTrainRequest.getTrainScenarioExcCsvPath(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 TRAIN.scenario_out_csv_path 参数
        addParamsFromList(commandParts, "++TRAIN.scenario_out_csv_path", modelTrainRequest.getTrainScenarioOutCsvPath(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 EVAL
        // .points_bin_path 参数
        addParamsFromList(commandParts, "++EVAL.points_bin_path", modelTrainRequest.getEvalPointsBinPath(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 EVAL.stl_path 参数
        addParamsFromList(commandParts, "++EVAL.stl_path", modelTrainRequest.getEvalStlPath(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 EVAL.data_dir 参数
        addParamsFromList(commandParts, "++EVAL.data_dir", modelTrainRequest.getEvalDataDir(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 EVAL.snapshots_path 参数
        addParamsFromList(commandParts, "++EVAL.snapshots_path", modelTrainRequest.getEvalSnapshotsPath(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 EVAL.scenario_exc_csv_path 参数
        addParamsFromList(commandParts, "++EVAL.scenario_exc_csv_path", modelTrainRequest.getEvalScenarioExcCsvPath(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 EVAL.scenario_out_csv_path 参数
        addParamsFromList(commandParts, "++EVAL.scenario_out_csv_path", modelTrainRequest.getEvalScenarioOutCsvPath(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 TRAIN.epochs 参数
        addParamsFromString(commandParts, "++TRAIN.epochs", modelTrainRequest.getTrainCount(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 TRAIN.lr_scheduler.learning_rate
        addParam(commandParts, "++TRAIN.lr_scheduler.learning_rate", modelTrainRequest.getTrainLrSchedulerLearningRate());

        addParam(commandParts, "++TRAIN.eval_freq", modelTrainRequest.getVerifFreq());

        addParam(commandParts, "++EVAL.vis_freq", "1");
        addParam(commandParts, "++EVAL.vis_result", "1");
//        addParam(commandParts, "EVAL.eval_during_training", "true");
//        addParam(commandParts, "EVAL.max_out_points", modelConfiguration.getModelEvalMaxOutPoints());
//        addParam(commandParts, "TRAIN.max_out_points", modelConfiguration.getModelTrainEvalMaxOutPoints());
//        addParamFromNumber(commandParts, "++EVAL.subsample", modelConfiguration.getEvalSubsample());
//        addParamFromNumber(commandParts, "++TRAIN.subsample", modelConfiguration.getTrainSubsample());


        addParamFromNumber(commandParts,"++log_freq", modelTrainRequest.getLogFreq());
        addParamFromNumber(commandParts,"++num_workers", modelTrainRequest.getNumWorkers());
        addParamFromStringList(commandParts,"++DATA.sdf_spatial_resolution", modelTrainRequest.getSdfSpatialResolution());
        addParamsConvertBoolean(commandParts, "++DATA.apply_log", modelTrainRequest.getApplyLog());
        addParamFromNumber(commandParts,"++MODEL.radius_in",  modelTrainRequest.getRadiusIn());
        addParamFromNumber(commandParts,"++MODEL.radius_out", modelTrainRequest.getRadiusOut());
        addParamFromNumber(commandParts,"++MODEL.embed_dim", modelTrainRequest.getEmbedDim());
        addParamFromStringList(commandParts,"++MODEL.hidden_channels", modelTrainRequest.getHiddenChannels());
        addParamFromStringList(commandParts,"++MODEL.fno_modes", modelTrainRequest.getFnoModes());
        addParamFromNumber(commandParts,"++MODEL.fno_hidden_channels", modelTrainRequest.getFnoHiddenChannels());
        addParamFromNumber(commandParts,"++MODEL.fno_out_channels", modelTrainRequest.getFnoOutChannels());
        addParamFromNumber(commandParts,"++MODEL.fno_domain_padding",modelTrainRequest.getFnoDomainPadding());
        addParamFromNumber(commandParts,"++MODEL.adain_embed_dim",modelTrainRequest.getAdainEmbedDim());
        addParamFromNumber(commandParts,"++MODEL.fno_n_layers",modelTrainRequest.getFnoNLayers());
        addParam(commandParts,"++MODEL.fno_skip",modelTrainRequest.getFnoSkip());
        //推测参数
        addParam(commandParts,"++MODEL.out_style","denorm");
        addParamFromNumber(commandParts,"++TRAIN.max_out_points",modelTrainRequest.getTrainMaxOutPoints());
        addParamFromNumber(commandParts,"++TRAIN.subsample",modelTrainRequest.getTrainSubsample());
        addParam(commandParts,"++TRAIN.weight_decay",modelTrainRequest.getWeightDecay());
        addParamFromNumber(commandParts,"++TRAIN.save_freq",modelTrainRequest.getSaveFreq());
        addParamFromNumber(commandParts,"++TRAIN.lr_scheduler.gamma",modelTrainRequest.getGamma());
        addParamFromNumber(commandParts,"++TRAIN.lr_scheduler.decay_steps",modelTrainRequest.getDecaySteps());

        //允许步长
        addParamsConvertBoolean(commandParts,"++MODEL.time_embed",modelTrainRequest.getModelTimeEmbed());

        addParamFromNumber(commandParts,"++EVAL.max_out_points",modelTrainRequest.getEvalMaxOutPoints());
        addParamFromNumber(commandParts,"++EVAL.subsample",modelTrainRequest.getEvalSubsample());
        if (modelTrainRequest.getEvalDataDir().isEmpty()
                || modelTrainRequest.getEvalSnapshotsPath().isEmpty()
                || modelTrainRequest.getEvalScenarioExcCsvPath().isEmpty()
                ||modelTrainRequest.getEvalScenarioOutCsvPath().isEmpty()
                ||modelTrainRequest.getEvalPointsBinPath().isEmpty()
                ||modelTrainRequest.getEvalStlPath().isEmpty())
        {
            addParamsConvertBoolean(commandParts,"++EVAL.eval_during_training",0);
        }else {
            addParamsConvertBoolean(commandParts,"++EVAL.eval_during_training",1);
        }
        // 构建完整命令（关键修改点）
        String[] fullCommand = new String[]{
                "/bin/bash",
                "-c",
                String.join(" ", commandParts)
                // 合并为单个命令字符串
        };

        log.info("Final command: " + Arrays.toString(fullCommand));

        // 构建执行命令（注意参数分隔）
            CreateContainerResponse container = null;

            try {
                // 创建容器配置（关键修改点）
                container = dockerClient.createContainerCmd(imageName)
                        .withName(containerName)
                        .withHostConfig(HostConfig.newHostConfig()
                                .withBinds(new Bind(hostConfigDir, new Volume(containerConfigPath)),
                                        new Bind(modelConfiguration.getModelContainerHostInputPath(),
                                                new Volume(modelConfiguration.getModelContainerVolumeInputPath())
                                        ),
                                        new Bind(modelConfiguration.getMinioOutputPath(),
                                                new Volume(modelConfiguration.getModelTrainMinioPath())
                                        )

                                )  // 挂载卷[1,4](@ref)
                                .withNetworkMode("host")
                                // 网络模式[1](@ref)
                                .withShmSize(64L * 1024 * 1024 * 1024)
                                // 64GB共享内存[8](@ref)
                                .withDeviceRequests(List.of(
                                        // GPU配置[2,5](@ref)
                                        new DeviceRequest()
                                                .withDriver("nvidia")
                                                .withCount(-1)
                                                .withCapabilities(List.of(List.of("gpu")))
                                ))
                        )
                        .withEnv(  // 环境变量配置[5,7](@ref)
                                "NVIDIA_DRIVER_CAPABILITIES=compute,utility",
                                "NVIDIA_VISIBLE_DEVICES=all"
                                // 容器级可见设备
                        )
                        .withWorkingDir(modelDefaultWorkSpace)
                        // 工作目录[4](@ref)
                        .withCmd(fullCommand)
                        .exec();
                // 启动容器
                dockerClient.startContainerCmd(container.getId()).exec();
                log.info("GPU容器启动成功！ID: " + container.getId());
            } catch (NotFoundException e) {
                log.error("镜像不存在: " + imageName);
            } catch (ConflictException e) {
                log.error("容器名称冲突: " + containerName);

            } finally {
                if (dockerClient != null) {
                    dockerClient.close();
                    log.info("关闭 DockerClient 成功");
                }
            }
        assert container != null;
        return "train" + "_" + container.getId() + "_" + modelTrainRequest.getTaskId() + "_" + uuidPath;
    }
    // 辅助方法处理参数格式
    private void addParam(List<String> list, String key, Object value) {
        if (value == null) {
            return; // 如果值为 null，直接返回
        }
        String stringValue = String.valueOf(value); // 将任意类型转换为字符串
        if (stringValue.isEmpty()) {
            return; // 如果转换后的字符串为空，直接返回
        }
        // 移除字符串中的空格，并添加到列表
        list.add(key + "=" + stringValue.replace(" ", ""));
    }
    private void addParamFix(List<String> list, String key, Object value) {

        String stringValue = String.valueOf(value); // 将任意类型转换为字符串
        if (stringValue.isEmpty()) {
            return; // 如果转换后的字符串为空，直接返回
        }
        // 移除字符串中的空格，并添加到列表
        list.add(key + "=" + stringValue.replace(" ", ""));
    }




    public List<String> getModelFileList(String modelTaskId) {
        String folderPath = minioFolderPathSub(modelTaskId);
        String pathPrefix = "model_address/" + folderPath + "/vtp/";
        MinioClient minioClient = createMinioClient();
        List<String> fileUrls = new ArrayList<>();

        try {
            // 检查存储桶是否存在
            boolean bucketExists = minioClient.bucketExists(
                    BucketExistsArgs.builder()
                            .bucket(modelConfiguration.getBucketName())
                            .build()
            );
            if (!bucketExists) {
                log.error("Bucket '{}' 不存在！", modelConfiguration.getBucketName());
                return new ArrayList<>();
            }

            // 列出指定路径下的所有 .vtp 文件（递归子目录）
            Iterable<Result<Item>> results = minioClient.listObjects(
                    ListObjectsArgs.builder()
                            .bucket(modelConfiguration.getBucketName())
                            .prefix(pathPrefix)
                            .recursive(true)
                            .build()
            );
            for (Result<Item> result : results) {
                Item item = result.get();
                if (!item.isDir() && item.objectName().endsWith(".vtp")) {
                    String objectName = item.objectName();
                    String fullUrl = String.format(
                            "%s/%s/%s",
                            modelConfiguration.getMinioEndpoint(),
                            modelConfiguration.getBucketName(),
                            objectName
                    );
                    fileUrls.add(fullUrl);
                }
            }
            log.info("找到 {} 个 .vtp 文件，路径前缀: {}", fileUrls.size(), pathPrefix);
        } catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
            log.error("MinIO 认证或连接失败: {}", e.getMessage(), e);
        } catch (ErrorResponseException | InsufficientDataException | InternalException |
                 InvalidResponseException | ServerException | XmlParserException e) {
            log.error("MinIO 操作失败: {}", e.getMessage(), e);
        } catch (Exception e) {
            log.error("未知错误: {}", e.getMessage(), e);
        }
        return fileUrls;
    }

    public List<String> getReasonFileList(String modelTaskId) {
        String folderPath = minioFolderPathSub(modelTaskId);
        // 使用 Paths.get() 规范化路径，避免注入攻击
        String pathPrefix = Paths.get("model_address", folderPath).toString() + "/";

        MinioClient minioClient = createMinioClient();
        List<String> fileUrls = new ArrayList<>();

        try {
            // 检查存储桶是否存在
            boolean bucketExists = minioClient.bucketExists(
                    BucketExistsArgs.builder()
                            .bucket(modelConfiguration.getBucketName())
                            .build()
            );
            if (!bucketExists) {
                log.error("Bucket '{}' 不存在！", modelConfiguration.getBucketName());
                return new ArrayList<>();
            }

            // 列出指定路径下的所有文件（包含子目录）
            Iterable<Result<Item>> results = minioClient.listObjects(
                    ListObjectsArgs.builder()
                            .bucket(modelConfiguration.getBucketName())
                            .prefix(pathPrefix)
                            .recursive(true) // 递归子目录（根据需求保留）
                            .build()
            );

            for (Result<Item> result : results) {
                Item item = result.get();
                if (!item.isDir() && item.objectName().endsWith(".vtp")) { // 关键修改：仅保留 .vtp 文件
                    String objectName = item.objectName();
                    String fullUrl = String.format(
                            "%s/%s/%s",
                            modelConfiguration.getMinioEndpoint(),
                            modelConfiguration.getBucketName(),
                            objectName
                    );
                    fileUrls.add(fullUrl);
                }
            }

            log.info("找到 {} 个 .vtp 文件，路径前缀: {}", fileUrls.size(), pathPrefix);
        } catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
            log.error("MinIO 认证或连接失败: {}", e.getMessage(), e);
        } catch (ErrorResponseException | InsufficientDataException | InternalException |
                 InvalidResponseException | ServerException | XmlParserException e) {
            log.error("MinIO 操作失败: {}", e.getMessage(), e);
        } catch (Exception e) {
            log.error("未知错误: {}", e.getMessage(), e);
        }

        return fileUrls;
    }

    /**
     * 删除minio上模型推理结果
     *
     * @param modelTaskId
     */
    public ResponseEntity<String> deleteTrainResult(String modelTaskId) {
        if (StringUtils.isEmpty(modelTaskId) || StringUtils.isBlank(modelTaskId)){
            return ResponseEntity.ok("modelTaskId is Null");
        }
        String folderPath = minioFolderPathSub(modelTaskId);
        log.info("删除模型推理结果: {}", folderPath);
        String deletePath = "model_address/" + folderPath + "/";
        MinioClient minioClient = createMinioClient();

        String bucketName = modelConfiguration.getBucketName();
        Iterable<Result<Item>> results = minioClient.listObjects(
                ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .prefix(deletePath)
                        //递归列出所有嵌套文件和目录
                        .recursive(true)
                        .build()
        );
        //列出所有待删除对象
        List<DeleteObject> deleteList = new ArrayList<>();
        try {
            //遍历删除对象
            for (Result<Item> result : results) {
                Item item = result.get();
                //跳过目录标记
                if (!item.isDir()) {
                    deleteList.add(new DeleteObject(item.objectName()));
                }
            }
            //批量删除
            if (deleteList.isEmpty()) {
                log.info("------删除路径{}为空------", deletePath);
                return ResponseEntity.ok("no such path");
            }
            //添加目录本身
            deleteList.add(new DeleteObject(deletePath));

            log.info("------删除路径{}：文件开始删除------", deletePath);
            Iterable<Result<DeleteError>> deleteResults = minioClient.removeObjects(
                    RemoveObjectsArgs.builder()
                            .bucket(bucketName)
                            .objects(deleteList)
                            .build());

            //检查删除错误
            for (Result<DeleteError> result : deleteResults) {
                DeleteError err = result.get();
                if (err != null) {
                    log.error("{}文件删除失败：{}", err.objectName(), err.message());
                    return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                            .body("false");
                }
            }
            log.info("------删除路径{}：文件删除结束------", deletePath);
        } catch (MinioException | IOException | NoSuchAlgorithmException | InvalidKeyException e) {
            log.error("未知错误: ", e);
            return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                    .body("false");
        }
        return ResponseEntity.ok("true");
    }


    public String  getTrainErr(String  modelTaskId){
        String containerId = extractContainerId(modelTaskId);
        if (StringUtils.isEmpty(containerId)) {
            return ("Invalid modelTaskId format");
        }
        // 使用StringBuilder存储日志内容
        final StringBuilder logContent = new StringBuilder();
        try (
                ResultCallback.Adapter<Frame> callback = new ResultCallback.Adapter<Frame>() {
                    @Override
                    public void onNext(Frame frame) {
                        logContent.append(new String(frame.getPayload()));
                    }
                };
                DockerClient dockerClient = DockerClientBuilder.getInstance().build()
        ) {

            // 执行日志获取命令
            dockerClient.logContainerCmd(containerId)
                    .withStdErr(true)     // 包含错误输出
                    .withTimestamps(true) // 不包含时间戳
                    .exec(callback)
                    .awaitCompletion(10, TimeUnit.SECONDS); // 设置超时时间
            return logContent.toString();
        } catch (Exception e) {
            log.error("获取容器日志错误：{}", e.getMessage());
            return "Error: " + e.getMessage();
        }
    }

    public String getTrainLog(String modelTaskId) {
        String containerId = extractContainerId(modelTaskId);
        if (StringUtils.isEmpty(containerId)) {
            return ("Invalid modelTaskId format");
        }
        // 使用StringBuilder存储日志内容
        final StringBuilder logContent = new StringBuilder();
        // 创建日志回调对象
        try (
                ResultCallback.Adapter<Frame> callback = new ResultCallback.Adapter<Frame>() {
                    @Override
                    public void onNext(Frame frame) {
                        logContent.append(new String(frame.getPayload()));
                    }
                };
                DockerClient dockerClient = DockerClientBuilder.getInstance().build()
        ) {

            // 执行日志获取命令
            dockerClient.logContainerCmd(containerId)
                    .withStdOut(true)     // 包含标准输出
                    .withStdErr(true)     // 包含错误输出
                    .withTailAll()        // 获取所有日志
                    .withTimestamps(true) // 不包含时间戳
                    .exec(callback)
                    .awaitCompletion(10, TimeUnit.SECONDS); // 设置超时时间
            return logContent.toString();
        } catch (Exception e) {
            log.error("获取容器日志错误：{}", e.getMessage());
            return "Error: " + e.getMessage();
        }
    }
    //通过minio获取日志
    public String getTrainLogByMinIo(String modelTaskId) {
        log.info("modelTaskId: " + modelTaskId);
        String folderPath = minioFolderPathSub(modelTaskId);
        log.info("folderPath: " + folderPath);
        String pathPrefix = "model_address/" + folderPath + "/";

        MinioClient minioClient = createMinioClient();

        try {
            Iterable<Result<Item>> results = minioClient.listObjects(
                    ListObjectsArgs.builder()
                            .bucket(modelConfiguration.getBucketName())
                            .prefix(pathPrefix)
                            .recursive(true)
                            .build());

            for (Result<Item> result : results) {
                Item item = result.get();
                String objectName = item.objectName();
                //训练/推理日志
                if (objectName.endsWith("train.log") || objectName.endsWith("infer_continuous.log")) {
                    log.info("Found log file: " + objectName);
                    try (InputStream stream = minioClient.getObject(
                            GetObjectArgs.builder()
                                    .bucket(modelConfiguration.getBucketName())
                                    .object(objectName)
                                    .build())) {
                        return new String(stream.readAllBytes(), StandardCharsets.UTF_8);
                    }
                }
            }
        } catch (Exception e) {
            log.info("获取日志错误：{}", e.getMessage());
            return "Error: " + e.getMessage();
        }
        return null;
    }

    public String getTrainLogByOrder(String modelTaskId) {
        String containerId = extractContainerId(modelTaskId);
        if (StringUtils.isEmpty(containerId)) {
            return ("Invalid modelTaskId format");
        }
        // 使用StringBuilder存储日志内容
        final StringBuilder logContent = new StringBuilder();
        // 创建日志回调对象
        try (
                ResultCallback.Adapter<Frame> callback = new ResultCallback.Adapter<Frame>() {
                    @Override
                    public void onNext(Frame frame) {
                        logContent.append(new String(frame.getPayload()));
                    }
                };
                DockerClient dockerClient = DockerClientBuilder.getInstance().build()
        ) {

            // 执行日志获取命令
            dockerClient.logContainerCmd(containerId)
                    .withStdOut(true)     // 包含标准输出
                    .withStdErr(true)     // 包含错误输出
                    .withTailAll()        // 获取所有日志
                    .withTimestamps(true) // 不包含时间戳
                    .exec(callback)
                    .awaitCompletion(10, TimeUnit.SECONDS); // 设置超时时间
            return logContent.toString();
        } catch (Exception e) {
            log.error("获取容器日志错误：{}", e.getMessage());
            return "Error: " + e.getMessage();
        }
    }

    public Map<String, String> getTrainList(String modelTaskId) {
        String folderPath = minioFolderPathSub(modelTaskId);
        String pathPrefix = "model_address/" + folderPath + "/";

        MinioClient minioClient = createMinioClient();
        String dataUrl = null;
        String pdUrl = null;
        StringBuilder evalUrl = new StringBuilder();
        StringBuilder csvUrl=new StringBuilder();

        try {
            Iterable<Result<Item>> results = minioClient.listObjects(
                    ListObjectsArgs.builder()
                            .bucket(modelConfiguration.getBucketName())
                            .prefix(pathPrefix)
                            .recursive(true) // 设置为递归以查找子目录中的文件
                            .build()
            );

            for (Result<Item> result : results) {
                Item item = result.get();
                if (!item.isDir()) {
                    if (item.objectName().contains("/json/")) {
                        evalUrl.append(String.format("%s/%s/%s,", modelConfiguration.getMinioEndpoint(), modelConfiguration.getBucketName(), item.objectName()));
                    }
                    if (item.objectName().contains("/csv/")){
                        csvUrl.append(String.format("%s/%s/%s,", modelConfiguration.getMinioEndpoint(), modelConfiguration.getBucketName(), item.objectName()));
                    }

                    if (item.objectName().endsWith(".jsonl")) {
                        dataUrl = String.format("%s/%s/%s", modelConfiguration.getMinioEndpoint(), modelConfiguration.getBucketName(), item.objectName());
                    } else if (item.objectName().endsWith("checkpoints/latest.pdparams")) {
                        pdUrl = String.format("%s/%s/%s", modelConfiguration.getMinioEndpoint(), modelConfiguration.getBucketName(), item.objectName());
                    }
                }
            }
            if (dataUrl == null) {
                log.warn("未找到有效的 .jsonl 文件");
            }
            if (pdUrl == null) {
                log.warn("未找到有效的 last.pdparams 文件");
            }
        } catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
            log.error("操作失败: ", e);
        } catch (Exception e) {
            log.error("未知错误: ", e);
        }
        Map<String, String> response = new HashMap<>();
        response.put("dataUrl", dataUrl != null ? dataUrl : "");
        response.put("pdUrl", pdUrl != null ? pdUrl : "");
        response.put("evalUrl", !StringUtils.isEmpty(evalUrl) ? evalUrl.substring(0, evalUrl.length() - 1):"");
        response.put("csvUrl", !StringUtils.isEmpty(csvUrl) ? csvUrl.substring(0, csvUrl.length() - 1):"");


        return response;
    }

    public String generateCharId() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 12);
    }

    public String minioFolderPathSub(String minioPathFolder) {
        // 找到第一个和第二个下划线的位置
        Pattern pattern = Pattern.compile("([a-zA-Z0-9]+_[a-zA-Z0-9]+)$");
        Matcher matcher = pattern.matcher(minioPathFolder);
        String taskIdWithUuid = "";
        if (matcher.find()) {
            taskIdWithUuid = matcher.group(1);
        } else {
            System.out.println("未找到匹配内容");
        }
        return taskIdWithUuid;
    }

    private void addParamsFromList(List<String> commandParts, String key, List<String> paths, String prefix) {
        if (paths == null || paths.isEmpty()) {
            return;
        }

        String targetBase = prefix;
        List<String> processedPaths = new ArrayList<>();

        for (String path : paths) {
            if (path == null) {
                continue;
            }
            // 替换 URL 前缀
            String replacedPath = replaceUrlPrefix(path, targetBase);
            processedPaths.add(replacedPath);
        }

        if (!processedPaths.isEmpty()) {
            // 为每个路径加单引号，保证 Hydra 正确解析
            List<String> quotedPaths = processedPaths.stream()
                    .map(p -> "'" + p + "'")
                    .collect(Collectors.toList());

            addParam(commandParts, key, "\""+"[" + String.join(",", quotedPaths) + "]"+"\"");
        }
    }


    private void addParamFromNumber(List<String> list, String key, Number value) {
        if (value != null) {
            list.add(key + "=" + value.toString().replace(" ", ""));
        }

    }


    private void addParamFromStringList(List<String> list, String key, String value){
        if (value == null || value.isEmpty()) {
            return;
        }
        list.add(key + "=" + "[" + value.replaceAll(" ","")+ "]");

    }
    //1，0 boolean转换
    public void addParamsConvertBoolean(List<String> list, String key, Integer value){
        if (value == null) {
            return;
        }
        boolean flag= value != 0;
        list.add(key + "=" + flag);
    }
    private void addParamsFromString(List<String> commandParts, String key, String path, String prefix) {
        if (path == null || path.isEmpty()) {
            return;
        }
        // 替换路径前缀
        String replacedPath = replaceUrlPrefix(path, prefix);
        // 直接添加为字符串，不包裹方括号
        addParam(commandParts, key, replacedPath);
    }
    private  void addParamAsNull(){
    }
    // 辅助方法：提取文件名（仅保留备用，实际未被使用）
    private String extractFileName(String path) {
        if (path == null || path.trim().isEmpty()) {
            return null;
        }
        int lastIndex = path.lastIndexOf("/");
        return (lastIndex != -1 && lastIndex < path.length() - 1)
                ? path.substring(lastIndex + 1)
                : null;
    }
    // 修改后的路径替换方法：直接替换远程URL前缀
    private String replaceUrlPrefix(String url, String newPrefix) {
        if (url == null || newPrefix == null) {
            return url;
        }
        // 定义远程URL前缀（例如：http://10.78.139.18:8000/zhongche）
        String remotePrefix = modelConfiguration.getMinioRemotePath();
        return url.replace(remotePrefix, newPrefix);
    }
    private MinioClient createMinioClient() {
        try {
            return MinioClient.builder()
                    .endpoint(modelConfiguration.getMinioEndpoint())
                    .credentials(modelConfiguration.getMinioAK(), modelConfiguration.getMinioSK())
                    .build();
        } catch (Exception e) {
            log.error("创建 MinioClient 失败: " + e.getMessage());
            throw new RuntimeException(e);
        }
    }
    @SneakyThrows
    public String reasonModel(ReasonModelRequest reasonModelRequest) {
        log.info("推理训练:{}", reasonModelRequest);
        // 1. 初始化 Docker 客户端（默认连接本地 Docker 守护进程）
        DockerClient dockerClient = DockerClientBuilder.getInstance().build();
        // 2. 定义容器参数
        String imageName = modelConfiguration.getModelImageVersion(); // 替换为你的镜像名称
        String containerName = modelConfiguration.getModelTrainName() + "-" + generateCharId();
        String hostConfigDir = modelConfiguration.getModelContainerHostPath(); // 宿主机配置文件目录
        String containerConfigPath = modelConfiguration.getModelContainerVolumePath(); // 容器内挂载路径
        String modelDefaultWorkSpace = modelConfiguration.getModelDefaultWorkPath(); // 模型默认工作路径
        String uuidPath = generateCharId();
        String minioBucketPath = modelConfiguration.getModelContainerVolumePath() + "/" + reasonModelRequest.getTaskId() + "_" + uuidPath;
        log.info("模型产物输出地址=>" + minioBucketPath);
        List<String> commandParts = new ArrayList<>();
        String cudaDevices = reasonModelRequest.getCudaVisbleDevices();
        commandParts.add("CUDA_VISIBLE_DEVICES=" + cudaDevices);
        // 按逗号分割 GPU 列表
        String[] devicesArray = cudaDevices.split(",");
        if (devicesArray.length >= 2) {
            // 当有两个或以上 GPU 时，使用分布式启动方式
            commandParts.add("python3.10");
            commandParts.add("-m");
            commandParts.add("paddle.distributed.launch");
            commandParts.add("main.py");
        } else {
            // 当只有一个 GPU 时，直接运行
            commandParts.add("python3.10");
            commandParts.add("main.py");
        }
        if (reasonModelRequest.getModelDatasetType().equals("motor")) {
            commandParts.add("-cn");
            commandParts.add("motor_thermal.yaml");
            log.info("当前数据集类型: " + reasonModelRequest.getModelDatasetType());
        } else if (reasonModelRequest.getModelDatasetType().equals("convertor")) {
            commandParts.add("-cn");
            commandParts.add("convertor_thermal.yaml");
            log.info("当前数据集类型: " + reasonModelRequest.getModelDatasetType());
        }
        commandParts.add("mode=infer_continuous");
        commandParts.add("output_dir=" + minioBucketPath.trim());
        //0表示模型推理，1表示设计优化
        Integer flag = reasonModelRequest.getFlag();
        // 添加 INFER.pretrained_model_path 参数
        addParamsFromString(commandParts, "++INFER.pretrained_model_path", reasonModelRequest.getInferPretrainedModelPath(),
                modelConfiguration.getModelTrainMinioPath());

        //由于设计优化和模型推理都使用的数组，此时判断没有意义，写死1
        // 添加 INFER.points_bin_path 参数
        addParamsWithFlag(1, commandParts, "++INFER.points_bin_path", reasonModelRequest.getInferPointBinPath(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 INFER.stl_path 参数
        addParamsWithFlag(1, commandParts, "++INFER.stl_path", reasonModelRequest.getInferStlPath(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 INFER.snapshot_path 参数
        addParamsFromString(commandParts, "++INFER.snapshot_path", reasonModelRequest.getInferSnapshotPath(),
                modelConfiguration.getModelTrainMinioPath());

        // 添加 INFER.scenario_exc_csv_path
        addParamsWithFlag(1, commandParts, "++INFER.scenario_exc_csv_path", reasonModelRequest.getInferScenarioExcCsvPath(),
                modelConfiguration.getModelTrainMinioPath());

        if (flag == 1 && !Objects.isNull(reasonModelRequest.getOriginalScheme())) {
            log.info("执行模型优化推参数路径替换");
            OriginalScheme originalScheme = reasonModelRequest.getOriginalScheme();
            addParamsFromString(commandParts, "++INFER.original_stl_path", originalScheme.getStl(),
                    modelConfiguration.getModelTrainMinioPath());
            addParamsFromString(commandParts, "++INFER.original_points_bin_path", originalScheme.getPointsBin(),
                    modelConfiguration.getModelTrainMinioPath());
            addParamsFromString(commandParts, "++INFER.original_snapshots_path", originalScheme.getSnapshotBin(),
                    modelConfiguration.getModelTrainMinioPath());
        }
        else{
            log.info("执行模型推理参数路径替换");
            commandParts.add("++INFER.original_stl_path" + "=null");
            commandParts.add("++INFER.original_points_bin_path" + "=null");
            commandParts.add("++INFER.original_snapshots_path" + "=null");
        }
        addParamFromNumber(commandParts, "++INFER.start_time", reasonModelRequest.getInferStartTime());
        addParamFromNumber(commandParts, "++INFER.end_time", reasonModelRequest.getInferEndTime());
        addParamFromNumber(commandParts, "++INFER.step", reasonModelRequest.getInferStep());

        if(reasonModelRequest.getInferSubsample()==0)
        {
            addParamFromNumber(commandParts, "++INFER.subsample", modelConfiguration.getInferSubsample());
        }else {
            addParamFromNumber(commandParts, "++INFER.subsample", reasonModelRequest.getInferSubsample());
        }
        if (reasonModelRequest.getInferMaxOutPoints()==0){
            addParamFromNumber(commandParts, "++INFER.max_out_points", modelConfiguration.getInferMaxOutPoints());
        }
        else {
            addParamFromNumber(commandParts, "++INFER.max_out_points", reasonModelRequest.getInferMaxOutPoints());
        }
        addParam(commandParts, "++INFER.vis_result", "true");
        addParam(commandParts, "++INFER.vis_freq", "1");
        addParam(commandParts,"++MODEL.out_style","denorm");
        String[] fullCommand = new String[]{
                "/bin/bash",
                "-c",
                String.join(" ", commandParts)  // 合并为单个命令字符串
        };
        log.info("Final command: " + Arrays.toString(fullCommand));
        // 构建执行命令（注意参数分隔）
        CreateContainerResponse container = null;
        try {
            // 创建容器配置（关键修改点）
            container = dockerClient.createContainerCmd(imageName)
                    .withName(containerName)
                    .withHostConfig(HostConfig.newHostConfig()
                            .withBinds(new Bind(hostConfigDir, new Volume(containerConfigPath)),
                                    new Bind(modelConfiguration.getModelContainerHostInputPath(),  // 模型用户上传的文件映射
                                            new Volume(modelConfiguration.getModelContainerVolumeInputPath()))   // 模型用户上传的文件映射到容器内路径
                                    ,
                                    new Bind(modelConfiguration.getMinioOutputPath(),
                                            new Volume(modelConfiguration.getModelTrainMinioPath())
                                    )
                            )  // 挂载卷[1,4](@ref)
                            .withNetworkMode("host")  // 网络模式[1](@ref)
                            .withShmSize(64L * 1024 * 1024 * 1024)  // 64GB共享内存[8](@ref)
                            .withDeviceRequests(List.of(  // GPU配置[2,5](@ref)
                                    new DeviceRequest()
                                            .withDriver("nvidia")
                                            .withCount(-1)
                                            .withCapabilities(List.of(List.of("gpu")))
                            ))
                    )
                    .withEnv(  // 环境变量配置[5,7](@ref)
                            "NVIDIA_DRIVER_CAPABILITIES=compute,utility",
                            "NVIDIA_VISIBLE_DEVICES=all"  // 容器级可见设备
                    )
                    .withWorkingDir(modelDefaultWorkSpace)  // 工作目录[4](@ref)
                    .withCmd(fullCommand)
                    .exec();
            // 启动容器
            dockerClient.startContainerCmd(container.getId()).exec();
            log.info("GPU容器启动成功！ID: " + container.getId());

        } catch (NotFoundException e) {
            log.error("镜像不存在: " + imageName);
        } catch (ConflictException e) {
            log.error("容器名称冲突: " + containerName);
        }finally {
            if (dockerClient != null) {
                dockerClient.close();
                log.info("关闭 DockerClient 成功");
            }
        }
        assert container != null;
        return "train" + "_" + container.getId() + "_" + reasonModelRequest.getTaskId() + "_" + uuidPath;
    }
    /**
     * 模型推理何实际优化公用逻辑，但是部分字段需要根据类型决定docker参数数组还是字符串类 型
     */
    private void addParamsWithFlag(Integer flag, List<String> commandParts, String key, String path, String prefix) {
        if (flag == 1) {
            //设计优化强制用数组
            addParamsFromForceList(commandParts, key, path, prefix);
        } else if (flag == 0) {
            //推理模型只用字符串
            addParamsFromString(commandParts, key, path, prefix);
        }

    }
    //路径可能是单个值，也可能是多个值以逗号拼接，强制以数组形式
    private void addParamsFromForceList(List<String> commandParts, String key, String path, String prefix) {
        if (path == null || path.isEmpty()) {
            return;
        }
        String[] paths = path.split(",");
        addParamsFromList(commandParts, key, Arrays.asList(paths), prefix);
    }
    public Map<String, String> getReasonModelDataPath(String modelTaskId) {
        String folderPath = minioFolderPathSub(modelTaskId);
        String pathPrefix = "model_address/" + folderPath + "/";
        MinioClient minioClient = createMinioClient();
        Map<String, String> resultUrls = new HashMap<>();
        try {
            String jsonlFile = null;
            String csvFile = null;
            // 递归列出所有对象
            Iterable<Result<Item>> results = minioClient.listObjects(
                    ListObjectsArgs.builder()
                            .bucket(modelConfiguration.getBucketName())
                            .prefix(pathPrefix)
                            .recursive(true)
                            .build()
            );
            for (Result<Item> result : results) {
                Item item = result.get();
                if (!item.isDir()) {
                    String objectName = item.objectName();
                    log.info("找到文件: {}", objectName);
                    // 查找 .jsonl 文件
                    if (objectName.endsWith(".jsonl") && jsonlFile == null) {
                        jsonlFile = objectName;
                    }
                    String fileName = new File(objectName).getName();
                    if ("thermal_bounds.csv".equals(fileName)) {
                        csvFile = objectName;
                    }
                }
            }
            // 构造 JSONL 文件 URL
            if (jsonlFile != null) {
                String jsonlUrl = String.format(
                        "%s/%s/%s",
                        modelConfiguration.getMinioEndpoint(),
                        modelConfiguration.getBucketName(),
                        jsonlFile
                );
                resultUrls.put("jsonlUrl", jsonlUrl);
                log.info("模型任务 [{}] 成功找到 .jsonl 文件: {}", modelTaskId, jsonlUrl);
            } else {
                log.warn("模型任务 [{}] 未找到 .jsonl 文件，路径前缀: {}", modelTaskId, pathPrefix);
            }
            // 构造 CSV 文件 URL
            if (csvFile != null) {
                String csvUrl = String.format(
                        "%s/%s/%s",
                        modelConfiguration.getMinioEndpoint(),
                        modelConfiguration.getBucketName(),
                        csvFile
                );
                resultUrls.put("csvUrl", csvUrl);
                log.info("模型任务 [{}] 成功找到 thermal_bounds.csv 文件: {}", modelTaskId, csvUrl);
            } else {
                log.warn("模型任务 [{}] 未找到 thermal_bounds.csv 文件，路径前缀: {}", modelTaskId, pathPrefix);
            }

        } catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
            log.error("MinIO 操作失败，modelTaskId: {}", modelTaskId, e);
        } catch (Exception e) {
            log.error("未知错误，modelTaskId: {}", modelTaskId, e);
        }
        return resultUrls;
    }
    public Map<String, String> getOptimizeModelData(String modelTaskId) {
        String folderPath = minioFolderPathSub(modelTaskId);
        String pathPrefix = "model_address/" + folderPath + "/";
        MinioClient minioClient = createMinioClient();
        Map<String, String> resultUrls = new HashMap<>();
        List<String> jsonlUrls = new ArrayList<>();
        List<String> csvUrls = new ArrayList<>();
        try {
            // 递归列出所有对象
            Iterable<Result<Item>> results = minioClient.listObjects(
                    ListObjectsArgs.builder()
                            .bucket(modelConfiguration.getBucketName())
                            .prefix(pathPrefix)
                            .recursive(true)
                            .build()
            );
            for (Result<Item> result : results) {
                Item item = result.get();
                if (!item.isDir()) {
                    String objectName = item.objectName();
                    log.info("找到文件: {}", objectName);
                    // 查找 .jsonl 文件
                    if (objectName.endsWith(".jsonl")) {
                        String url = String.format(
                                "%s/%s/%s",
                                modelConfiguration.getMinioEndpoint(),
                                modelConfiguration.getBucketName(),
                                objectName
                        );
                        jsonlUrls.add(url);
                        log.info("模型任务 [{}] 成功找到 .jsonl 文件: {}", modelTaskId, url);
                    } else if (objectName.endsWith(".csv")) {
                        String url = String.format(
                                "%s/%s/%s",
                                modelConfiguration.getMinioEndpoint(),
                                modelConfiguration.getBucketName(),
                                objectName
                        );
                        csvUrls.add(url);
                        log.info("模型任务 [{}] 成功找到 .csv 文件: {}", modelTaskId, url);
                    }
                }
            }
        } catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
            log.error("MinIO 操作失败，modelTaskId: {}", modelTaskId, e);
        } catch (Exception e) {
            log.error("未知错误，modelTaskId: {}", modelTaskId, e);
        }
        resultUrls.put("jsonlUrl", String.join(",", jsonlUrls));
        resultUrls.put("csvUrl", String.join(",", csvUrls));
        return resultUrls;
    }
    @SneakyThrows
    public String getCombinedProgress(String modelTaskId) {
        String folderPath = minioFolderPathSub(modelTaskId);
        //  /model_address/model_task_id
        String pathPrefix = Paths.get(modelConfiguration.getMinioYongjiModelPrefix(), folderPath).toString() + "/";
        MinioClient minioClient = createMinioClient();

        try {
            List<Item> items = new ArrayList<>();
            Iterable<Result<Item>> results = minioClient.listObjects(
                    ListObjectsArgs.builder()
                            // zhongche
                            .bucket(modelConfiguration.getBucketName())
                            .prefix(pathPrefix)
                            .recursive(true) // 递归子目录
                            .build()
            );
            for (Result<Item> resultItem : results) {
                Item item = resultItem.get();
                if (!item.isDir() && item.objectName().endsWith(".jsonl")) {
                    items.add(item);
                }
            }
            if (!items.isEmpty()) {
                // 按最后修改时间降序排序，取最新文件
                items.sort(Comparator.comparing(Item::lastModified).reversed());
                for (Item item : items) {
                    String jsonlFilePath = item.objectName();
                    log.debug("处理文件: {}", jsonlFilePath);
                    try (InputStream stream = minioClient.getObject(
                            GetObjectArgs.builder()
                                    .bucket(modelConfiguration.getBucketName())
                                    .object(jsonlFilePath)
                                    .build()
                    )) {
                        BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8));
                        String lastLine = null;
                        String line;
                        while ((line = reader.readLine()) != null) {
                            lastLine = line;
                        }
                        if (lastLine != null) {
                            JsonNode jsonNode = OBJECT_MAPPER.readTree(lastLine);
                            // 优先尝试获取 epoch
                            if (jsonNode.has("epoch")) {
                                double epochValue = jsonNode.get("epoch").asDouble();
                                return String.valueOf(epochValue); // 直接返回，优先返回 epoch
                            }
                            // 如果 epoch 不存在，尝试 current_time
                            else if (jsonNode.has("current_time")) {
                                double currentTime = jsonNode.get("current_time").asDouble();
                                return String.valueOf(currentTime);
                            }
                        }
                    } catch (Exception e) {
                        log.error("读取文件 [{}] 失败", jsonlFilePath, e);
                    }
                }
            } else {
                log.warn("未找到 .jsonl 文件，路径: {}", pathPrefix);
            }
        } catch (Exception e) {
            log.error("操作失败，modelTaskId: {}", modelTaskId, e);
        }
        return "";
    }
    //容器状态
    @SneakyThrows
    public String getContainerStatus(String modelTaskId) {
        String containerId = extractContainerId(modelTaskId);
        if (StringUtils.isEmpty(containerId)) {
            return ("Invalid modelTaskId format");
        }
        try (DockerClient dockerClient = DockerClientBuilder.getInstance().build()) {
            InspectContainerResponse response = dockerClient.inspectContainerCmd(containerId).exec();

            InspectContainerResponse.ContainerState state = response.getState();
            response.getState();
            if (state != null) {
                return String.format(
                        "Status: %s | Running: %s | ExitCode: %s | Started At: %s | Finished At: %s",
                        state.getStatus(),
                        state.getRunning(),
                        state.getExitCodeLong(),
                        state.getStartedAt(),
                        state.getFinishedAt()
                );
            }
            return "Container not found";
        } catch (Exception e) {
            return "Error: " + e.getMessage();
        }
    }

    //分割_前的字符
    private String extractContainerId(String input) {
        String[] parts = input.split("_");
        if (parts.length < 2) {
            return null;
            // 格式不正确
        }
        return parts[1];
    }
    // 主方法：停止模型任务
    public String stopModel(String modelTaskId) {
        log.info("当前modelTaskId: {}", modelTaskId);
        try {
            // 1. 解析容器ID（根据你的modelTaskId格式）
            String containerId = extractContainerId(modelTaskId);
            if (StringUtils.isEmpty(containerId)) {
                return buildResponse(false, "Invalid modelTaskId format");
            }
            // 2. 停止容器
            boolean success = stopContainer(containerId);
            log.info("容器关闭成功出参,{}",success);
            if (success) {

                return buildResponse(true, "Container stopped successfully");
            } else {
                return buildResponse(false, "Failed to stop container");
            }
        } catch (Exception e) {
            log.info("exception,{}",e.getMessage());
            return buildResponse(false, "Internal error: " + e.getMessage());
        }
    }
    // 私有方法：停止容器
    private boolean stopContainer(String containerId) {
        try (DockerClient dockerClient = DockerClientBuilder.getInstance().build()) {

            dockerClient.stopContainerCmd(containerId).withTimeout(0).exec();
            return true;
        } catch (NotFoundException e) {
            log.info("当前容器已不存在,{}", containerId);
            return true;
        } catch (Exception e) {
            log.info("关闭容器出错,{},{}", containerId,e.getMessage());
            return false;
        }
    }
    //私有方法，删除并关闭容器
    private boolean removeContainer(String containerId) {
        try (DockerClient dockerClient = DockerClientBuilder.getInstance().build()) {
            dockerClient.removeContainerCmd(containerId)
                    .withForce(true)  // 强制删除（即使容器还在运行或异常状态）
                    .exec();
            log.info("已删除容器: {}", containerId);
            return true;
        } catch (NotFoundException e) {
            log.warn("删除容器失败，未找到容器: {}", containerId);
            return false;
        } catch (Exception e) {
            log.error("删除容器时发生异常: {}", containerId, e);
            return false;
        }
    }
    // 私有方法：构建响应结果
    private String buildResponse(boolean isSuccess, String message) {
        return String.valueOf(isSuccess);
    }
    //异步清理资源删除容器
    private void cleanupContainer(DockerClient dockerClient, CreateContainerResponse container) {
        CompletableFuture.runAsync(() -> {
            try {
                // 停止并删除容器
                if (container != null ) {
                    removeContainer(container.getId());
                    log.info("异步停止并删除容器成功");
                }
                // 关闭 DockerClient 连接
                if (dockerClient != null) {
                    dockerClient.close();
                    log.info("异步关闭 DockerClient 成功");
                }
            } catch (Exception e) {
                log.error("异步清理资源时出错：", e);
            }
        });
    }
    //异步清理资源关闭删除容器，txt临时资源删除
    private void cleanupAsync(DockerClient dockerClient, CreateContainerResponse container, String localPath) {
        CompletableFuture.runAsync(() -> {
            try {
                // 删除本地临时目录
                File file = new File(localPath);
                deleteDirectory(file);
                log.info("异步删除目录成功");
                // 停止并删除容器
                if (container != null ) {
                    removeContainer(container.getId());
                    log.info("异步停止并删除容器成功");
                }
                // 关闭 DockerClient 连接
                if (dockerClient != null) {
                    dockerClient.close();
                    log.info("异步关闭 DockerClient 成功");
                }
            } catch (Exception e) {
                log.error("异步清理资源时出错：", e);
            }
        });
    }


    /**
     * 关闭并删除容器
     * @param modelTaskId
     * @return
     */
    public int removeContainerById(String modelTaskId) {
        String containerId = extractContainerId(modelTaskId);
        // 获取容器 ID
        if (StringUtils.isEmpty(containerId)) {
            return -1;
        }
        DockerClient dockerClient = DockerClientBuilder.getInstance().build();
        try {
            InspectContainerResponse  container = dockerClient.inspectContainerCmd(containerId).exec();
            if ("running".equals(container.getState().getStatus())) {
                dockerClient.stopContainerCmd(containerId).exec();
            }
            dockerClient.removeContainerCmd(containerId).withForce(true).exec();
            log.info("已删除容器: {}", containerId);
            return 0;
        } catch (NotFoundException e) {
            log.error("容器不存在: {}", containerId);
            return 0;
        } catch (Exception e) {
            log.error("删除容器时出错: {}", e.getMessage());
            return -3;
        } finally {
            try {
                dockerClient.close();
            }catch (Exception e){
                log.error("关闭客户端连接时出错: {}", e.getMessage());
            }
        }
    }

    public  String addParamFile(String url){
        String s = replaceUrlPrefix(url, modelConfiguration.getModelTrainMinioPath());
        return s;

    }



//    public static void main(String[] args) {
//        String url = "http://172.30.5.5:9000/zhongche/1746701214873_dd445d8f-5e3f-48eb-b5e0-fcc2596c8dd6/scenario_2/Cabinet_Solid_scaled_to_m.stl";
//        String s = addParamFile(url);
//        System.out.println(s);
//    }
    @SneakyThrows
    public String render(RenderRequest request) {
        log.info("render数据:{}", request);
        // . 初始化 Docker 客户端（默认连接本地 Docker 守护进程）
        DockerClient dockerClient = DockerClientBuilder.getInstance().build();
        //  定义容器参数
        String imageName = modelConfiguration.getModelImageVersion(); // 替换为你的镜像名称
        String containerName = modelConfiguration.getModelTrainName() + "-" + generateCharId();
        String hostConfigDir = modelConfiguration.getModelContainerHostPath(); // 宿主机配置文件目录
        String containerConfigPath = modelConfiguration.getModelContainerVolumePath(); // 容器内挂载路径
        String modelDefaultWorkSpace = modelConfiguration.getModelDefaultWorkPath(); // 模型默认工作路径
        String uuidPath = generateCharId();
        List<String> commandParts = new ArrayList<>();
        commandParts.add("python3.10");
        commandParts.add("main.py");
        commandParts.add("mode=export");

        commandParts.add("++RENDER.snapshot_dir="+addParamFile(request.getRenderSnapshotDir()));
        commandParts.add("++RENDER.points_bin_path="+addParamFile(request.getRenderPointsBinPath()));
        commandParts.add("++RENDER.vtp_dump_dir="+addParamFile(request.getRenderVtpDumpDir()));
        // 构建完整命令（关键修改点）
        String[] fullCommand = new String[]{
                "/bin/bash",
                "-c",
                String.join(" ", commandParts)
                // 合并为单个命令字符串
        };
        log.info("Final command: " + Arrays.toString(fullCommand));
        // 构建执行命令（注意参数分隔）
        CreateContainerResponse container = null;
        try {
            // 创建容器配置（关键修改点）
            container = dockerClient.createContainerCmd(imageName)
                    .withName(containerName)
                    .withHostConfig(HostConfig.newHostConfig()
                            .withBinds(new Bind(hostConfigDir, new Volume(containerConfigPath)),
                                    new Bind(modelConfiguration.getModelContainerHostInputPath(),  // 模型用户上传的文件映射
                                            new Volume(modelConfiguration.getModelContainerVolumeInputPath()))   // 模型用户上传的文件映射到容器内路径
                                    ,
                                    new Bind(modelConfiguration.getMinioOutputPath(),
                                            new Volume(modelConfiguration.getModelTrainMinioPath())
                                    )
                            )  // 挂载卷[1,4](@ref)
                            .withNetworkMode("host")  // 网络模式[1](@ref)
                            .withShmSize(64L * 1024 * 1024 * 1024)  // 64GB共享内存[8](@ref)
                            .withDeviceRequests(List.of(  // GPU配置[2,5](@ref)
                                    new DeviceRequest()
                                            .withDriver("nvidia")
                                            .withCount(-1)
                                            .withCapabilities(List.of(List.of("gpu")))
                            ))
                    )
                    .withEnv(  // 环境变量配置[5,7](@ref)
                            "NVIDIA_DRIVER_CAPABILITIES=compute,utility",
                            "NVIDIA_VISIBLE_DEVICES=all"  // 容器级可见设备
                    )
                    .withWorkingDir(modelDefaultWorkSpace)  // 工作目录[4](@ref)
                    .withCmd(fullCommand)
                    .exec();
            // 启动容器

//            ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(container.getId())
//                    .withAttachStdout(true)
//                    .withAttachStderr(true)
//                    .withCmd(
//                            "python", "generate_snapshot_path.py",
//                            "--scenario_out", modelConfiguration.getModelContainerVolumeInputPath() + "/minioData/" + minioPath,
//                            "--type", minioRequestTxt.getType()
//                    )
            dockerClient.startContainerCmd(container.getId()).exec();
            log.info("GPU容器启动成功！ID: " + container.getId());

        } catch (NotFoundException e) {
            log.error("镜像不存在: " + imageName);
        } catch (ConflictException e) {
            log.error("容器名称冲突: " + containerName);
        }finally {
            if (dockerClient != null) {
                dockerClient.close();
                log.info("关闭 DockerClient 成功");
            }
        }
        assert container != null;
        return "train" + "_" + container.getId() + "_" + request.getTaskId() + "_" + uuidPath;
    }

    public ResponseEntity<String> deleteRederResult(Long id) {
        if (Objects.isNull(id) || NumberUtil.equals(id,0L)){
            return ResponseEntity.ok("id is null or id is 0L");
        }
        MinioClient minioClient = createMinioClient();
        String floader="/model_temp_vtp/"+id+"/";
        String bucketName = modelConfiguration.getBucketName();
        Iterable<Result<Item>> resultIterable = minioClient.listObjects(
                ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .prefix(floader)
                        .recursive(true)
                        .build()
        );
        ArrayList<DeleteObject> deleteObjects = new ArrayList<>();
        try {
            for (Result<Item> temp:resultIterable){
                Item item = temp.get();
                if (!item.isDir()){
                    deleteObjects.add(new DeleteObject(item.objectName()));
                }
            }
            if (CollectionUtil.isEmpty(deleteObjects)){
                return ResponseEntity.ok("no such path");
            }
            deleteObjects.add(new DeleteObject(floader));
            Iterable<Result<DeleteError>> results = minioClient.removeObjects(
                    RemoveObjectsArgs.builder()
                            .objects(deleteObjects)
                            .bucket(bucketName)
                            .build()
            );
            for (Result<DeleteError> result : results) {
                DeleteError deleteError = result.get();
                if (ObjectUtil.isNotNull(deleteError)) {
                    log.info("删除出现error，objectName,{}deleteError,{}", deleteError.objectName(), deleteError.message());
                    return ResponseEntity.ok(deleteError.message());
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return ResponseEntity.ok("delete success");
    }
}